package it.uni.bo.monitoring.protocol.unmarshaller;

import static it.uni.bo.monitoring.service.StaticFields.QUERY_SQL_EVENT;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_SQL_EVENT_PARAMETER;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_SQL_VIOLATION;

import it.uni.bo.monitoring.protocol.server.DataObject;
import it.uni.bo.monitoring.protocol.unmarshaller.analysis.DataAnalysis;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;


public class LazyInsertEvent extends Thread {
	
	private BlockingQueue<DataObject> rdoToEvent;
	private BlockingQueue<byte[]> rdoToRemove;
	private DataAnalysis da;
	private SessionFactory factory;
	private BlockingQueue<EventInfo> eventData;
	private Logger l;
	private static final String ERROR_ROLLING_BACK="error rolling back transaction";
	private static final String INFO_INSERT="inserisco in Event i record";
	
	public LazyInsertEvent(BlockingQueue<DataObject> rdoToEvent, BlockingQueue<byte[]> rdoToRemove, LinkedBlockingQueue<EventInfo> eventData, DataAnalysis da, SessionFactory factory) { 
		l = Logger.getLogger(this.getClass());	
		this.rdoToEvent=rdoToEvent;
		this.rdoToRemove= rdoToRemove;
		this.eventData=eventData;
		this.da= da;
		this.factory=factory;
	}

	public synchronized void run() {
		ArrayList<byte[]> rdoArray = new ArrayList<byte[]>();
		Transaction tx =null;
		Session session = null;
		if(factory!=null)
		while(true){
			try {
				rdoArray.clear();
				do{
					DataObject object=rdoToEvent.take();
					rdoToEvent.remove(object);
					if(object!=null){
						EventInfo ei=	da.analyse(object);
						if(ei!=null){
							if((session==null) || (!session.isOpen()))
								session=factory.openSession();
							if((tx == null) || (!tx.isActive()))
								tx=session.beginTransaction();
							Query query = session.createSQLQuery(QUERY_SQL_EVENT);
							query.setBinary(0, ei.getIdE());
							query.setCharacter(1, ei.getDirection());
							query.setLong(2,ei.getTimestamp());
							query.setLong(3,ei.getSeqNumber());
							query.setString(4,ei.getSession());
							query.setLong(5,ei.getIdA());
							query.setLong(6, ei.getIdU());
							query.setLong(7, ei.getIdWso());
							query.setLong(8,ei.getIdWs());
							l.info("Hibernate: "+QUERY_SQL_EVENT+" --[ "+new String(ei.getIdE())+" "+ei.getDirection()+" "+ei.getTimestamp()+" "+ei.getSeqNumber()+" "+ei.getSession()+" "+ei.getIdA()+" "+ei.getIdU()+" "+ei.getIdWso()+" "+ei.getIdWs()+" ]");
							query.executeUpdate();
			
							Set<EventParameterInfo> epiSet = ei.getEventParameterInfo();
							if(epiSet!=null){
								Iterator<EventParameterInfo> itePar = epiSet.iterator();

								while(itePar.hasNext()){
									EventParameterInfo epi=itePar.next();
									Query query2 = session.createSQLQuery(QUERY_SQL_EVENT_PARAMETER);
									query2.setString(0,epi.getValue());
									query2.setInteger(1,epi.getPosition());
									query2.setLong(2,epi.getWop());
									query2.setBinary(3,epi.getIdE());

									l.info("Hibernate: "+QUERY_SQL_EVENT_PARAMETER+" --[ "+epi.getValue()+" "+epi.getPosition()+" "+epi.getWop()+" "+new String(epi.getIdE())+" ]");
									query.executeUpdate();
								}
							}
							if (tx != null && tx.isActive())
								tx.commit();
							//l.info(INFO_INSERT +" ("+num+")");
							eventData.add(ei);
						}
						else
							rdoArray.add(object.getKey());
					}
				}while(rdoToEvent.size()>0);
			} catch (InterruptedException e) {
				l.error(e.getMessage());
			} catch (RuntimeException e) {
				if (tx != null && tx.isActive()) {
					try {
						tx.rollback();
					} catch (HibernateException e1) {
						l.error(ERROR_ROLLING_BACK);
					}
					throw e;
				}
			}
			finally{
				if ((session!=null) && (session.isOpen())) 
					session.close(); 
				if(rdoArray.size()>0){
					//l.info("rimuovo dal Gestore Eventi "+rdoArray.size());
					rdoToRemove.addAll(rdoArray);
				}
			}
		}
	}

}